<template>
	<div class="flowable-model-container">
		<el-card shadow="hover" class="mb10">
			<el-button icon="el-icon-close" class="ml10" @click="onActFlowClose">关闭</el-button>
			<el-button icon="el-icon-check" v-if="flowButton.actFlowSave" type="primary" class="ml10" @click="onActFlowSave">保存</el-button>
			<el-button icon="el-icon-top" v-if="flowButton.actFlowSend" type="primary" class="ml10" @click="onActFlowSend">发送</el-button>
			<el-button icon="el-icon-bottom" v-if="flowButton.actFlowReject" type="primary" class="ml10" @click="onActFlowReject">驳回</el-button>
			<el-button icon="el-icon-back" v-if="flowButton.actFlowBack" type="primary" class="ml10" @click="onActFlowBack">撤办</el-button>
			<el-button icon="el-icon-delete" v-if="flowButton.actFlowTrash" type="danger" class="ml10" @click="onActFlowTrash">作废</el-button>
			<!-- 操作插槽 -->
			<slot name="button"></slot>
		</el-card>
		<el-card shadow="hover">
			<div class="mb20">
				<el-breadcrumb separator="/">
					<el-breadcrumb-item>流程名称：{{flowData.modelName}}</el-breadcrumb-item>
					<el-breadcrumb-item>流程类型：{{flowData.category}}</el-breadcrumb-item>
					<el-breadcrumb-item>当前环节：{{flowData.currentNode ? flowData.currentNode : '开始'}}</el-breadcrumb-item>
				</el-breadcrumb>
			</div>
			<el-tabs model-value="flow-form" @tab-click="onTabClick">
				<el-tab-pane :label="formLabel" name="flow-form" class="form-slot">
					<!-- 表单插槽 -->
					<slot name="form"></slot>
				</el-tab-pane>
				<el-tab-pane label="流程记录" name="flow-record" v-if="flowData.businessKey != null && flowData.businessKey != ''">
					<div class="block">
						<el-timeline style="padding: 0 5px;">
							<el-timeline-item v-for="(item, i) in flowActivity" :key="i" type="primary" placement="top" :timestamp="item.startTime">
								<p style="color: var(--el-text-color-regular);line-height: 32px;">环节名称：{{item.activityName}}</p>
								<p style="color: var(--el-text-color-regular);line-height: 32px;">办理时间：{{item.startTime}} ~ {{item.endTime}}</p>
								<p style="color: var(--el-text-color-regular);line-height: 32px;" v-if="item.assignee != null">办理人员：{{item.assignee}}</p>
								<p style="color: var(--el-text-color-regular);line-height: 32px;" v-if="item.deleteReason != null">办理意见：{{item.deleteReason}}</p>
								<p style="color: var(--el-text-color-regular);line-height: 32px;" v-if="item.comment != null">办理意见：{{item.comment}}</p>
							</el-timeline-item>
						</el-timeline>
					</div>
				</el-tab-pane>
				<el-tab-pane label="流程图" name="flow-image" v-if="flowData.businessKey != null && flowData.businessKey != ''">
					<div class="block" style="text-align: center;padding: 15px;">
						<el-image :src="flowDiagram">
							<template #error>
								<div class="image-slot" style="font-size: 24px;">
									<i class="el-icon-loading"></i>
								</div>
							</template>
						</el-image>
					</div>
				</el-tab-pane>
				<!-- 标签页插槽 -->
				<slot name="tabs"></slot>
			</el-tabs>
		</el-card>
		
		<!-- 办理窗口 -->
		<el-dialog title="提交下一步" v-model="flowDialog.isShowDialog">
			<el-form ref="submitNextTaskFormRef" :model="flowDialog.formData" :rules="flowDialog.formRules" label-width="95px">
				<el-row :gutter="35">
					<el-col>
						<el-form-item label="当前环节：">
							<el-input v-model="flowDialog.currentNode.name" readonly></el-input>
						</el-form-item>
					</el-col>
					<el-col>
						<el-form-item label="流转操作：">
							<el-radio-group v-model="flowDialog.formData.handleId">
								<el-radio v-for="(item, i) in flowDialog.handles" :key="i" :label="item.id" @change="onFlowHandleChange">{{item.name == '' ? '提交' : item.name}}</el-radio>
							</el-radio-group>
						</el-form-item>
					</el-col>
					<el-col>
						<el-collapse accordion v-model="flowDialog.accordion.active" @change="onAccordionChange">
							<el-collapse-item v-for="(nextNode, i) in flowDialog.nextNodes" :key="i" :name="nextNode.id">
								<template #title>
									<span class="ml10" style="color: var(--el-text-color-regular);">下一环节：{{nextNode.name}}</span>
								</template>
								<div style="text-align: center">
									<el-transfer v-model="nextNode.checkAssignees"
											filterable
											:titles="['待选人员', '已选人员']"
											:props="{ 'key': 'loginName', 'label': 'loginName'}"
											:data="nextNode.nextAssignees"
											@change="onTransferChange"
										>
										<template #default="{ option }">
											<span>{{ option.loginName }} ({{ option.userName }})</span>
										</template>
									</el-transfer>
								</div>
							</el-collapse-item>
						</el-collapse>
					</el-col>
					<el-col class="mt15" v-if="flowDialog.currentNode.assignee != '$INITIATOR'">
						<el-form-item label="办理意见：" prop="message">
							<el-input type="textarea" v-model="flowDialog.formData.message" placeholder="请输入办理意见" clearable></el-input>
						</el-form-item>
					</el-col>
					<!-- 实际业务上传去实现 -->
					<!-- <el-col>
						<el-form-item label="办理附件：" prop="attachments">
							
						</el-form-item>
					</el-col> -->
				</el-row>
			</el-form>
			<template #footer>
				<span class="dialog-footer">
					<el-button @click="onCancel">取 消</el-button>
					<el-button type="primary" @click="onSubmit">发 送</el-button>
				</span>
			</template>
		</el-dialog>
		
	</div>
</template>

<script lang="ts">
import { ref, toRefs, reactive, getCurrentInstance, onMounted, defineComponent, watch } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { 
	getFlowModelerInfo, 
	flowTaskStart, 
	getFlowButtons, 
	getFlowNextHandles, 
	getFlowNextNodes, 
	getFlowNextAssignee, 
	flowTaskHandle, 
	flowTaskTrash, 
	flowTaskBack,
	flowTaskReject,
	getFlowActivitys, 
	getFlowDiagram,
} from '/@/api/flowable/task/index';

export interface FlowableState {
	formLabel: string,
	flowLoading: any,
	flowButton: any,
	flowActivity: any,
	flowDiagram : any,
	flowDialog: any,
	flowData: any,
}

export default defineComponent({
	name: 'flowableModel',
	props: {
		// 绑定值
		model: {
			type: Object,
			default: () => {},
		},
		// 流程模板标识
		modelKey: {
			type: String,
			default: () => '',
		},
		// 业务主键标识
		businessKey: {
			type: String,
			default: () => 'id',
		},
		// 业务名称标识
		flowNameKey : {
			type: String,
			default: () => 'title',
		},
		formLabel : {
			type: String,
			default: () => '表单信息',
		},
		// 回调函数方法
		callbackId: {
			type: String,
			default: () => '',
		},
		// 回调函数类型
		callbackType: {
			type: String,
			default: () => 'TypeScriptFunction',
		},
		// 视图类型标签页=tagview，弹窗页dialog
		viewKey: {
			type: String,
			default: () => 'tagview',
		},
	},
	components: { },
	setup(props, { emit }) {
		const submitNextTaskFormRef = ref();
		const route = useRoute();
		const { proxy } = getCurrentInstance() as any;
		const state = reactive<FlowableState>({
			formLabel: '',
			flowLoading: undefined,
			flowButton: {},
			flowActivity: [],
			flowDiagram : undefined,
			flowDialog: {
				isShowDialog: false,
				formData: {},
				currentNode: {},
				nextNode: {},
				handles: [],
				nextNodes: [],
				accordion: {
					active : '',
				},
				formRules : {
					message: { required: true, message: '办理意见不能为空', trigger: 'blur' },
				},
			},
			flowData: {
				instanceId: undefined,
				flowName: undefined,
				businessKey: undefined,
				deployId: undefined,
				tenantId: undefined,
				category: undefined,
				modelName: undefined,
				modelKey: undefined,
				callbackId: undefined,
				callbackType: undefined,
			},
		});
		// 加载流程引擎数据
		const loadFlowModelerInfo = (modelKey: string) => {
			getFlowModelerInfo({modelKey : modelKey}).then((res: any) => {
				if(res.code == 0){
					//组装流程信息
					Object.assign(state.flowData, res.data);
				}
			});
		};
		// 加载流程引擎按钮
		const loadFlowButtonsInfo = (businessKey: string) => {
			getFlowButtons(businessKey).then((res: any) => {
				if(res.code == 0){
					Object.assign(state.flowButton, res.data);
					flowFormReadonly();
				}
			});
		};
		// 流程表单只读
		const flowFormReadonly = () => {
			//不可操作表单伪代码
			if(state.flowButton.actFlowSave == false){
				const targetElement = document.querySelector('.form-slot') as HTMLElement;
				state.flowLoading = ElLoading.service({
					target: targetElement,
					fullscreen: false,
					background: 'rgba(255,255,255,0)',
					text: '',
					spinner: 'none',
				});
			}else{
				if(state.flowLoading){
					if(typeof state.flowLoading.close == 'function'){
						state.flowLoading.close();
					}
				}
			}
		}
		// 加载流程记录
		const loadFlowActivitysInfo = (businessKey: string) => {
			getFlowActivitys(businessKey).then((res: any) => {
				if(res.code == 0){
					Object.assign(state.flowActivity, res.data);
				}
			});
		};
		// 加载流程图
		const loadFlowDiagramInfo = (id: any) => {
			getFlowDiagram(id).then((res: any) => {
				const blob = new Blob([res]);
				var url = window.URL.createObjectURL(blob);
				state.flowDiagram = url;
			});
		}
		// 点击选项卡时
		const onTabClick = (tab: any) => {
			if('flow-record' == tab.props.name){
				loadFlowActivitysInfo(state.flowData.businessKey);
			}else if('flow-image' == tab.props.name){
				loadFlowDiagramInfo(state.flowData.businessKey);
			}
			emit('tab-click', tab);
		}
		// 刷新
		const onActFlowRefresh = () => {
			loadFlowButtonsInfo(state.flowData.businessKey);
		}
		// 关闭
		const onActFlowClose = () => {
			if(props.viewKey == 'tagview'){//默认:标签页
				proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
			}
			emit('form-close');
		};
		// 保存
		const onActFlowSave = () => {
			if(state.flowData.businessKey){
				emit('form-edit');
			}else{
				emit('form-save');
			}
		};
		// 流程实例
		const onActFlowStart = (data: any) => {
			Object.assign(state.flowData, data);
			state.flowData.flowName = data[props.flowNameKey];
			state.flowData.businessKey = data[props.businessKey];
			// 开启流程实例
			flowTaskStart(state.flowData).then((res: any) => {
				if(res.code === 0){
					ElMessage.success('启动成功');
					onActFlowRefresh();
				}
			});
		}
		// 发送
		const onActFlowSend = () => {
			state.flowDialog.isShowDialog = true;
			getFlowNextHandles(state.flowData.businessKey).then((res: any) => {
				if(res.code == 0){
					Object.assign(state.flowDialog, res.data);
					state.flowDialog.formData.handleId = state.flowDialog.handles[0]?.id;
					if(state.flowDialog.formData.handleId){
						onFlowHandleChange(state.flowDialog.formData.handleId);
					}
				}
			});
		};
		// 当操作变更时
		const onFlowHandleChange = (label: string) => {
			state.flowDialog.formData.handleId = label;
			getFlowNextNodes({businessKey: state.flowData.businessKey, handleId: state.flowDialog.formData.handleId}).then((res: any) => {
				if(res.code == 0){
					Object.assign(state.flowDialog.nextNodes, res.data);
					let nodeId = state.flowDialog.nextNodes[0]?.id;
					if(nodeId){
						state.flowDialog.accordion.active = nodeId;
						getFlowNextAssignee({businessKey: state.flowData.businessKey, handleId: state.flowDialog.formData.handleId, nodeId: state.flowDialog.accordion.active}).then((res: any) => {
							if(res.code == 0){
								for(let i =0; i < state.flowDialog.nextNodes.length; i++){
									if(state.flowDialog.nextNodes[i].id == state.flowDialog.accordion.active){
										state.flowDialog.nextNodes[i].nextAssignees = res.data;
										break;
									}
								}
							}
						});
					}
				}
			});
		};
		// 当手风琴环节变更时
		const onAccordionChange = (active: string) => {
			if(active){
				getFlowNextAssignee({businessKey: state.flowData.businessKey, handleId: state.flowDialog.formData.handleId, nodeId: state.flowDialog.accordion.active}).then((res: any) => {
					if(res.code == 0){
						for(let i =0; i < state.flowDialog.nextNodes.length; i++){
							if(state.flowDialog.nextNodes[i].id == state.flowDialog.accordion.active){
								state.flowDialog.nextNodes[i].nextAssignees = res.data;
								break;
							}
						}
					}
				});
			}
		}
		// 当穿梭窗改变时
		const onTransferChange = (values: any, direction: any, keys: any) => {
			if(direction == 'right'){
				//单项选择
				for(let i =0; i < state.flowDialog.nextNodes.length; i++){
					if(state.flowDialog.nextNodes[i].id == state.flowDialog.accordion.active){
						state.flowDialog.nextNodes[i].checkAssignees = [keys[0]];
						break;
					}
				}
			}
		}
		// 关闭弹窗
		const closeDialog = () => {
			state.flowDialog.isShowDialog = false;
			state.flowDialog.formData = {};
			state.flowDialog.currentNode = {};
			state.flowDialog.handles = [];
			state.flowDialog.nextNodes = [];
			submitNextTaskFormRef.value.resetFields();
		};
		// 取消
		const onCancel = () => {
			closeDialog();
		};
		// 发送
		const onSubmit = () => {
			submitNextTaskFormRef.value.validate((valid: any) => {
				let params = {
					businessKey: state.flowData.businessKey,
					handleId: state.flowDialog.formData.handleId,
					message: state.flowDialog.formData.message,
					assignees: [],
				}
				if(state.flowDialog.nextNodes && state.flowDialog.nextNodes.length > 0){
					for(let i = 0; i < state.flowDialog.nextNodes.length; i++){
						let item = state.flowDialog.nextNodes[i];
						if(item.checkAssignees && item.checkAssignees.length > 0){
							params.assignees.push({
								nodeId: item.id,
								userId: item.checkAssignees[0]
							});
						}else{
							if(item.outgoingFlows.length > 0){
								valid = false;
								ElMessage.warning(`下一环节【${item.name}】办理人不能为空`);
								break;
							}
						}
					}
				}
				if(valid){
					flowTaskHandle(params).then((res: any) => {
						if(res.code == 0){
							ElMessage.success('发送成功');
							closeDialog();
							onActFlowRefresh();
							onActFlowClose();
						}
					});
				}
			});
		}
		// 驳回
		const onActFlowReject = () => {
			ElMessageBox.prompt('确定驳回该条流程业务信息吗？', '提示', {
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				inputPlaceholder: '请输入驳回原因',
				inputType: 'textarea',
				inputValidator: (value) => {
					if(value && value.length > 0){
						return true;
					}else{
						return '驳回原因不能为空'
					}
				},
				type: 'warning',
			}).then(({value}) => {
				flowTaskReject({businessKey: state.flowData.businessKey, message: value}).then((res: any) => {
					if(res.code == 0){
						ElMessage.success('驳回成功');
						onActFlowRefresh();
						onActFlowClose();
					}
				});
			}).catch(() => {});
		};
		// 撤办
		const onActFlowBack = () => {
			ElMessageBox.confirm('确定撤办该条流程业务信息吗？', '提示', {
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				type: 'warning',
			}).then(() => {
				flowTaskBack({businessKey: state.flowData.businessKey}).then((res: any) => {
					if(res.code == 0){
						ElMessage.success('撤办成功');
						onActFlowRefresh();
						onActFlowClose();
					}
				});
			}).catch(() => {});
		};
		// 作废
		const onActFlowTrash = () => {
			ElMessageBox.confirm('确定作废该条流程业务信息吗？', '提示', {
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				type: 'warning',
			}).then(() => {
				flowTaskTrash({businessKey: state.flowData.businessKey}).then((res: any) => {
					if(res.code == 0){
						ElMessage.success('作废成功');
						onActFlowRefresh();
						onActFlowClose();
					}
				});
			}).catch(() => {});
		};
		// 页面加载时
		onMounted(() => {
			state.formLabel = props.formLabel;
			state.flowData.modelKey = props.modelKey;
			state.flowData.callbackId = props.callbackId;
			state.flowData.callbackType = props.callbackType;
			loadFlowModelerInfo(state.flowData.modelKey);
			loadFlowButtonsInfo(state.flowData.businessKey);
		});
		
		//监听model数据
		watch(()=>props.model[props.businessKey], (businessKey) => {
			state.flowData.businessKey = businessKey;
			loadFlowButtonsInfo(state.flowData.businessKey);
		}, {deep: true});
		
		return {
			submitNextTaskFormRef,
			onActFlowClose,
			onActFlowStart,
			onActFlowSave,
			onActFlowSend,
			onActFlowReject,
			onActFlowBack,
			onActFlowTrash,
			onActFlowRefresh,
			onFlowHandleChange,
			onAccordionChange,
			onTransferChange,
			onTabClick,
			onCancel,
			onSubmit,
			...toRefs(state),
		};
	}
});
</script>
<style scoped lang="scss">
.flowable-model-container{
	.el-transfer{
		width: 100%;
		--el-transfer-panel-width: 35%;
		--el-transfer-panel-body-height: 350px;
		:deep .el-transfer-panel__filter{
			max-height: 32px;
		}
		:deep .el-transfer-panel__list.is-filterable {
			scrollbar-width: thin;
		}
	}
	.el-transfer-right-footer{
		color:var(--el-text-color-secondary);
		font-size: 12px;
	}
}
</style>